#ifndef __OJ_MODEL_HPP__
#define __OJ_MODEL_HPP__

#include <iostream>
#include <string>
#include <unordered_map>
#include <fstream>
#include <cassert>
#include <cstring>
#include "../comm/log.hpp"
#include "../comm/util.hpp"

namespace ns_model
{
    using namespace ns_log;
    using namespace ns_util;

    /*题目类 主要是对于题目信息进行统一管理*/
    class Question
    {
    public:
        std::string _number; // 题目ID，唯一
        std::string _title;  // 题目标题
        std::string _star;   // 题目难度  简单 中等 困难
        int _cpu_limit;      // 题目要求的时间要求
        int _mem_limit;      // 题目要求的空间要求
        std::string _desc;   // 题目具体内容的描述
        std::string _header; // 题目预设给用户在线编译器的代码
        std::string _tail;   // 题目的测试用例，需要和_header拼接，形成完成代码
    };

    const std::string questins_list="./questions/questions.list";
    const std::string questins_path="./questions/";

    /*Model类 主要是对于数据进行管理，提供加载、获取、查找题目等功能*/
    class Model
    {
    private:
        std::unordered_map<std::string,Question> _questions;//将所有列表题目都加载进内存进行统一管理

    public:
        Model()
        {
            assert(LoadQuestionList(questins_list));
        }
        ~Model(){}
        
        /*加载列表所有题目*/
        /* ************************************
        *
        *题目编号 题目标题 题目难度 时间要求 空间要求
        * 
        * *************************************/
        bool LoadQuestionList(const std::string& question_list)
        {
            std::ifstream in(question_list,std::ios::in|std::ios::binary);
            if(in.is_open()==false)
            {
                LOG(FATAL)<<"加载题库失败，请检查是否存在文件！！！"<<"\n";
                return false;
            }

            /*循环读取*/
            std::string line;
            while(std::getline(in,line))
            {
                /*解析分割字符串*/
                std::vector<std::string> tokens;
                StringUtil::SplitString(line,&tokens," ");
                if(tokens.size()!=5)
                {
                    LOG(WARNING)<<"加载部分题目失败，请检查文件格式"<<"\n";
                    continue;
                }

                /*存储数据*/
                Question q;
                q._number=tokens[0];
                q._title=tokens[1];
                q._star=tokens[2];
                q._cpu_limit=atoi(tokens[3].c_str());
                q._mem_limit=atoi(tokens[4].c_str());

                std::string path=questins_path;
                path+=q._number;
                path+="/";

                FileUtil::ReadFile(path+"desc.txt",&(q._desc),true);
                FileUtil::ReadFile(path+"header.cc",&(q._header),true);
                FileUtil::ReadFile(path+"tail.cc",&(q._tail),true);

                _questions.insert({q._number,q});
            }

            LOG(INFO)<<"加载题库....成功"<<'\n';
            in.close();
            return true;
        }

        /*获取列表所有题目信息*/
        bool GetAllQuestions(std::vector<Question>* out)
        {
            if(_questions.empty()==true)
            {
                LOG(ERROR)<<"用户获取题库失败"<<"\n";
                return false;
            }
            for(const auto& q:_questions)
            {
                out->push_back(q.second);
            }
            return true;
        }

        /*根据题目编号指定获取题目信息*/
        bool GetOneQuestion(const std::string& number,Question* q)
        {
            auto iter=_questions.find(number);
            if(iter==_questions.end())
            {
                LOG(ERROR)<<"用户获取题目失败，题目编号："<<number<<"\n";
                return false;
            }
            *q=iter->second;
            return true;
        }
    };
}

#endif